﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using Eflong.KJFiles;
using Eflong.MonitoringLib.Event;
using Eflong.MonitoringLib.MonitoringUnit;

using Eflong.Structure;
using Eflong.Utility;

namespace Eflong.SocketClient
{
    public class Client : IDisposable
    {
        public const string NET_DISCONNECT = "与服务器联机失败";

        public const string NET_CONNECTED = "与服务器联机成功";

        /// <summary>
        /// 文件不存在
        /// </summary>
        public const string FILE_NOTEXISETS = "文件不存在";

        /// <summary>
        /// 数据文件不变化
        /// </summary>
        public const string FILE_NOTCHANGED = "数据文件不变化";

        /// <summary>
        /// 无法读取文件
        /// </summary>
        public const string FILE_NOTBEREAD = "无法读取文件";

        /// <summary>
        /// 没有测点项
        /// </summary>
        public const string FILE_NOITEMS = KJXXN_Files.FILE_NOITEMS;

        /// <summary>
        /// 套接字操作尝试一个无法连接的主机
        /// </summary>
        public const string NET_CONNECTED_ERROR = "套接字操作尝试一个无法连接的主机";

        /// <summary>
        /// 由于目标机器积极拒绝，无法连接
        /// </summary>
        public const string NET_CONNECTED_ERROR2 = "由于目标机器积极拒绝，无法连接";

        /// <summary>
        /// 与服务器不能联机，请检查网络是否正常，或服务器是否异常
        /// </summary>
        public const string NET_ERROR = "与服务器不能联机，请检查网络是否正常，或服务器是否异常";

        /// <summary>
        /// 向服务器发送测点定义信息
        /// </summary>
        public const string SEND_DEFINITION = "向服务器发送测点定义信息";

        /// <summary>
        /// 向服务器发送实时数据信息
        /// </summary>
        public const string SEND_DATAS = "向服务器发送实时数据信息";

        /// <summary>
        /// 实时数据信息不变化
        /// </summary>
        public const string DATA_NOTCHEANED = "实时数据信息不变化";

        /// <summary>
        /// 是否联网
        /// </summary>
        public bool HasServer = true;

        public Client( )
        {
            Init( );
        }

        public void Init( )
        {
            name = "client";

            networkMode = NetworkModes.Client;

            IsRunning = true;

            IsPause = false;

            PoolingInterval = 5;

            DataChangedInterval = 2.0f;// 5;// 4;// 3; 数据文件不变化间隔

            dispatcher = new EventDispatcher( this );

            clientThread = new ClientSocketThread( this );

            manager = CoalMineUnitManager.Instance( );

            m_checkLoginResetEvent = new ManualResetEvent( true );

            m_checkConnectedResetEvent = new ManualResetEvent( true );

            m_checkQueryCoalMineRequestAck = new ManualResetEvent( true );

            m_checkQueryDataRequestAck = new ManualResetEvent( true );

            m_checkQueryDefinitionRequestAck = new ManualResetEvent( true );

            m_checkSendDataAck = new ManualResetEvent( true );

            updateTime = DateTime.Now;
        }

        public string name { get; set; }

        public ClientSocket clientSocket { get; set; }

        public ClientSocketThread clientThread { get; set; }

        public EventDispatcher dispatcher { get; set; }

        public bool Connected { get; set; }

        /// <summary>
        /// 登录成功
        /// </summary>
        public bool Logined { get; set; }

        /// <summary>
        /// 更新时刻
        /// </summary>
        private DateTime updateTime { get; set; }

        /// <summary>
        /// 检查是否连接成功
        /// </summary>
        public ManualResetEvent m_checkConnectedResetEvent { get; set; }

        /// <summary>
        /// 检查是否登录成功
        /// </summary>
        public ManualResetEvent m_checkLoginResetEvent { get; set; }

        /// <summary>
        /// 检查是否查询到CoalMine信息
        /// </summary>
        public ManualResetEvent m_checkQueryCoalMineRequestAck { get; set; }

        /// <summary>
        /// 检查是否查询到Definition信息
        /// </summary>
        public ManualResetEvent m_checkQueryDefinitionRequestAck { get; set; }

        /// <summary>
        /// 检查是否查询到Data信息
        /// </summary>
        public ManualResetEvent m_checkQueryDataRequestAck { get; set; }

        /// <summary>
        /// 检查服务器是否需要发送数据
        /// </summary>
        public ManualResetEvent m_checkSendDataAck { get; set; }

        /// <summary>
        /// 发送事件信号
        /// </summary>
        internal AutoResetEvent autoSended = new AutoResetEvent( false );

        /// <summary>
        /// 接收事件信号
        /// </summary>
        internal AutoResetEvent autoReceived = new AutoResetEvent( false );

        /// <summary>
        /// 联网矿信息改变事件
        /// </summary>
        public CoalMineChangedHandler onCoalMineChanged { get; set; }

        /// <summary>
        /// 定义更新事件
        /// </summary>
        public DefinitionChangedHandler onDefinitionChanged { get; set; }

        /// <summary>
        /// 数据更新事件
        /// </summary>
        public DataChangedHandler onDataChanged { get; set; }

        /// <summary>
        /// 查询联网矿信息完成
        /// </summary>
        public QueryCoalMineInfoHandler onQueryCoalMineInfoCompleted { get; set; }

        /// <summary>
        /// 服务器通信中断
        /// </summary>
        public EventHandler OnServerCommBreak { get; set; }

        /// <summary>
        /// 错误信息事件
        /// </summary>
        public ErrorMessageHandler onErrorMessage { get; set; }

        /// <summary>
        /// 显示信息事件
        /// </summary>
        public ShowMessageHandler onShowMessage { get; set; }

        public DispatchMessageHandler onMessageShow { get; set; }

        public DispatchErrorHandler onErrorDeal { get; set; }

        public string userId { get; set; }

        public string passward { get; set; }

        public Packet loginPacket { get; set; }

        public LoginStruct stLogin;

        public bool IsRunning { get; set; }

        /*
         *  暂停
         */

        public bool IsPause { get; set; }

        /// <summary>
        /// 处于空闲状态
        /// </summary>
        public bool IsIdle { get; set; }

        /// <summary>
        /// 信息查询或更新间隔
        /// </summary>
        public float PoolingInterval { get; set; }

        /// <summary>
        ///  数据不变化间隔
        ///  分钟
        /// </summary>
        public float DataChangedInterval { get; set; }

        public CoalMineUnitManager manager { get; set; }

        /// <summary>
        /// 联机时刻
        /// </summary>
        public DateTime ConnectedTime { get; set; }

        /// <summary>
        /// 中断时刻
        /// </summary>
        public DateTime DisConnectedTime { get; set; }

        /// <summary>
        /// 重新登录连接
        /// </summary>
        public bool ReLogined = false;

        protected System.Windows.Forms.ListBox lb_Info;
        protected System.Windows.Forms.Form form;

        //

        public void SetMainForm( Form form , ListBox lb )
        {
            this.form = form;
            this.lb_Info = lb;
            this.onMessageShow += new DispatchMessageHandler( dispatcher_onMessageShow );
            this.onErrorDeal += new DispatchErrorHandler( dispatcher_onErrorDeal );
        }

        private void dispatcher_onMessageShow( object sender , MessageEventArgs e )
        {
            ThreadPool.QueueUserWorkItem( this.threadCallMessage , e.Message );
        }

        /// <summary>
        /// 工作线程
        /// </summary>
        private Thread workThread;

        /// <summary>
        /// 开始工作
        /// </summary>
        public virtual void Start( )
        {
            workThread = new Thread( new ThreadStart( this.DoConnectOrQueryOrUpdate ) );
            workThread.Priority = ThreadPriority.BelowNormal;
            workThread.IsBackground = true;
            workThread.Start( );
            LogWrapper.Logger.Info( "Client Start" );
        }

        /// <summary>
        /// 停止工作
        /// </summary>
        public virtual void Stop( )
        {
            if ( this.IsRunning )
            {
                this.IsRunning = false;
                this.IsPause = true;

                if ( workThread != null )
                {
                    workThread.Join( );
                    workThread = null;
                }

                if ( Connected && Logined )
                {
                    this.m_checkLoginResetEvent.Reset( );
                    Logout( userId , passward , dwMethodType + 1 , nNetworkMode + 1 );
                    if ( this.m_checkLoginResetEvent.WaitOne( 800 , false ) )
                    {
                        if ( Logined )
                        {
                            LogWrapper.Logger.Info( "没有退出" );
                        }
                        else
                        {
                            LogWrapper.Logger.Info( "已经退出" );
                        }
                    }
                    Connected = false;
                    Logined = false;
                }
                LogWrapper.Logger.Info( "Client Stop" );

                this.clientSocket.Disconnect( );
            }
            else
            {
                LogWrapper.Logger.Info( "Client Stoped" );
            }
        }

        /// <summary>
        /// 网络工作模式 Client or Bridge or Gate
        /// </summary>
        public NetworkModes networkMode { get; set; }

        /// <summary>
        /// 建立与服务器的连接
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        public void ConnectToServer( string ip , int port )
        {
            Connected = false;
            Logined = false;

            clientSocket = new ClientSocket( this ) { ServerHost = ip , Port = port };

            clientSocket.onCompleted += new SocketConnectedHandler( clientSocket_onCompleted );

            clientSocket.OnSended += new ClientSocket.SendCompleted( clientSocket_OnSended );
            dispatcher.onPacketDeal += new DispatchPacketDealHander( dispatcher_onPacketDeal );
            dispatcher.onPacketIn += new DispatchPacketInHandler( dispatcher_onPacketIn );
        }

        /// <summary>
        /// 接受到系统返回的数据包
        /// </summary>
        /// <param name="packet"></param>
        private void clientSocket_OnPacketReceived( Packet packet )
        {
            autoReceived.Set( );
            LogWrapper.Logger.Debug( "clientSocket_OnPacketReceived" );
        }

        private void clientSocket_OnSended( bool successorfalse )
        {
            autoSended.Set( );
            if ( successorfalse )
            {
            }
        }

        /// <summary>
        /// 处理错误信息的处理函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dispatcher_onErrorDeal( object sender , MessageEventArgs e )
        {
            if ( onErrorMessage != null )
            {
                onErrorMessage( this , new MessageEventArgs( e.Message , e.Id ) );
            }
            else
            {
                DispatchMessage( e.Message );
            }
        }

        /// <summary>
        /// 接收到联网服务器发来的数据包
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dispatcher_onPacketIn( object sender , SocketEventArgs e )
        {
            Packet packet = null;
            do
            {
                try
                {
                    packet = clientThread.TakePacketReceived( );
                    if ( packet != null )
                    {
                        PerformUpdatePacket( packet );
                    }
                }
                catch ( Exception ex )
                {
                    LogWrapper.Logger.Error( "dispatcher_onPacketIn" );
                    LogWrapper.Logger.Error( ex.Message );
                }
            } while ( packet != null );
        }

        private void dispatcher_onPacketDeal( object sender , EventArgs e )
        {
            autoReceived.Set( );
            LogWrapper.Logger.Debug( "dispatcher_onPacketDeal autoReceived.Set()" );
        }

        private void clientSocket_onCompleted( object sender , EventArgs e )
        {
            Connected = clientSocket.IsConnected( );
            if ( !IsRunning )
            {
                if ( OnServerCommBreak != null )
                {
                    OnServerCommBreak( this , null );
                }
                return;
            }

            Logined = false;
            if ( Connected )
            {
                LogWrapper.Logger.Info( "连接成功" );
                DispatchMessage( NET_CONNECTED );
                ConnectedTime = DateTime.Now;
            }
            else
            {
                LogWrapper.Logger.Info( "连接失败" );
                DisptchExceptionMessage( NET_DISCONNECT );
                DisConnectedTime = DateTime.Now;
                if ( networkMode == NetworkModes.Client )
                {
                    // 对Client 模式采取，设置中断，对Bridge、Gate 不设置
                    SetHaltAllCoalMine( );
                }
            }
            m_checkConnectedResetEvent.Set( );
        }

        /// <summary>
        /// 设置服务器各矿联网中断
        /// </summary>
        public void SetHaltAllCoalMine( )
        {
            LogWrapper.Logger.Warn( "设置服务器各矿联网中断 SetHaltAllCoalMine " );

            foreach ( BaseCoalMineUnit coalMineUnit in manager.GetAllCoalMineUnits( ) )
            {
                try
                {
                    if ( coalMineUnit != null )
                    {
                        coalMineUnit.HaltAllMonitoringUnits( );
                        if ( OnServerCommBreak == null && onDataChanged != null )
                        {
                            if ( onDataChanged != null )
                            {
                                onDataChanged( this , new MessageEventArgs( "联网中断" , coalMineUnit.m_nId ) );
                            }
                        }
                        Thread.Sleep( 100 );
                    }
                }
                catch ( Exception ex )
                {
                    LogWrapper.Logger.Error( "SetHaltAllCoalMine: " + ex.Message );
                }
            }

            if ( OnServerCommBreak != null )
            {
                OnServerCommBreak( this , null );
            }
        }

        public uint dwMethodType { get; set; }

        public int nNetworkMode { get; set; }

        /// <summary>
        /// 一般登录
        /// </summary>
        /// <param name="user"></param>
        /// <param name="passward"></param>
        /// <param name="dwMethodType"></param>
        /// <param name="nNetworkMode"></param>
        public void Login( string user , string passward , uint dwMethodType , int nNetworkMode )
        {
            this.userId = user;
            this.passward = passward;
            this.dwMethodType = dwMethodType;
            this.nNetworkMode = nNetworkMode;

            stLogin = new LoginStruct( user , passward , dwMethodType , nNetworkMode , 1 );
            loginPacket = new Packet( ( uint )stLogin.length( ) , stLogin.GetByteArray( ) );
        }

        /// <summary>
        /// 一般退出
        /// </summary>
        /// <param name="user"></param>
        /// <param name="passward"></param>
        /// <param name="dwMethodType"></param>
        /// <param name="nNetworkMode"></param>
        public void Logout( string user , string passward , uint dwMethodType , int nNetworkMode )
        {
            this.userId = user;
            this.passward = passward;

            LoginStruct loginStruct = new LoginStruct( user , passward , dwMethodType , nNetworkMode , 1 );
            loginPacket = new Packet( ( uint )loginStruct.length( ) , loginStruct.GetByteArray( ) );

            SendRequst( loginPacket , VCS_MT_TYPES.VCS_MT_LOGOUT );
        }

        /// <summary>
        /// 按客户端方式登录
        /// </summary>
        /// <param name="user"></param>
        /// <param name="passward"></param>
        public void LoginForClient( string user , string passward )
        {
            networkMode = NetworkModes.Client;
            Login( user , passward , LoginStruct.VCS_MT_LOGIN , LoginStruct.LOGIN_CLIENT );
        }

        /// <summary>
        /// 按客户端方式退出
        /// </summary>
        /// <param name="user"></param>
        /// <param name="passward"></param>
        public void LogoutForClient( string user , string passward )
        {
            Logout( user , passward , LoginStruct.VCS_MT_LOGOUT , LoginStruct.LOGOUT_CLIENT );
        }

        private Random r = new Random( DateTime.Now.Millisecond );

        /// <summary>
        /// 连接服务器或发送请求
        /// </summary>
        public virtual void DoConnectOrQueryOrUpdate( )
        {
            do
            {
                IsIdle = false;

                if ( !IsPause )
                {
                    // 进行本地更新

                    LocalUpdate( );

                    if ( !HasServer )
                    {
                        Logined = true;
                    }
                    if ( HasServer && !IsNetNormal( ) )
                    {
                        // 网络没有实时数据更新时，应该断开，再重新连接
                        DisptchExceptionMessage( "断开与服务器连接 " );
                        clientSocket.Disconnect( );
                    }

                    // 非暂停
                    if ( !HasServer || clientSocket.IsConnected( ) && Logined )
                    {
                        // 网络正常，且登录成功

                        DoQueryOrUpdate( );
                    }
                    else
                    {
                        Logined = false;

                        DoConnectOrLogin( );

                        if ( Logined )
                        {
                            // 延迟几秒再上传数据
                            Thread.Sleep( r.Next( 5000 ) );
                            ReLogined = true;
                            DoQueryOrUpdate( );
                            ReLogined = false;
                        }
                    }
                }
                double dt = 0;
                DateTime tm = DateTime.Now;

                IsIdle = true;
                do
                {
                    Thread.Sleep( 100 );
                    if ( Connected && Logined && ( IsFileTimeChanged( ) || IsFileTimeChanged2( ) ) )
                    {
                        break;
                    }
                    dt = DateTime.Now.Subtract( tm ).TotalSeconds;
                } while ( IsRunning && dt < PoolingInterval );
            } while ( IsRunning );
        }

        /// <summary>
        /// 建立网络连接并发送登录请求
        //bool bFirstLogined = true;
        /// </summary>
        public virtual void DoConnectOrLogin( )
        {
            if ( !clientSocket.IsConnected( ) )
            {
                // 建立连接
                m_checkConnectedResetEvent.Reset( );
                try
                {
                    DispatchMessage( "连接服务器... " );
                    clientSocket.Connect( );
                }
                finally
                {
                }

                m_checkConnectedResetEvent.WaitOne( 800 , false );
            }
            if ( clientSocket.IsConnected( ) )
            {
                Thread.Sleep( 1300 );

                // 发送登录请求
                SendLoginRequest( );
            }
        }

        /// <summary>
        /// 本地更新
        /// </summary>
        protected virtual void LocalUpdate( )
        {
        }

        private int loginNotBackCount = 0;

        /// <summary>
        /// 发送登录请求
        /// </summary>
        protected void SendLoginRequest( )
        {
            loginPacket = new Packet( ( uint )stLogin.length( ) , stLogin.GetByteArray( ) );
            LogWrapper.Logger.Info( "发送登录请求 login" );
            PacketAck packetAck = SendRequst( loginPacket , VCS_MT_TYPES.VCS_MT_LOGIN );

            DispatchMessage( "发送登录请求 " );

            autoReceived.WaitOne( 1000 * 10 );

            TakeCurrentPacketAck( packetAck );

            if ( packetAck.packetIn != null )
            {
                Logined = true;
                loginNotBackCount = 0;
                updateTime = DateTime.Now;
                LogWrapper.Logger.Info( "登录成功 " );
                DispatchMessage( "登录成功 " );
                if ( networkMode != NetworkModes.Client )
                {
                    // 设置系统的时间，和服务器时间同步
                    LogWrapper.Logger.Info( "设置系统的时间，和服务器时间同步 " );
                    SetSysTimeToServer( packetAck.packetIn );
                }
            }
            else
            {
                if ( networkMode != NetworkModes.Client )
                {
                    loginNotBackCount++;
                    LogWrapper.Logger.Warn( "未接到服务器返回的登录包" );
                    DisptchExceptionMessage( "未接到服务器返回的登录包" );
                    if ( loginNotBackCount >= 3 )
                    {
                        clientSocket.Disconnect( );
                        loginNotBackCount = 0;
                    }
                }
            }
        }

        /// <summary>
        /// 按网络模式，发送更新或查询
        /// </summary>
        public virtual void DoQueryOrUpdate( )
        {
            switch ( networkMode )
            {
                case NetworkModes.Client:

                    // 发送查询请求
                    SendClientQueryRequsts( false );
                    break;

                case NetworkModes.Bridge:

                    // 发送网桥更新请求
                    LogWrapper.Logger.Debug( "发送网桥更新请求" );
                    SendBridgeUpdateRequest( );
                    break;

                case NetworkModes.Gate:

                    // 发送网关更新请求
                    LogWrapper.Logger.Debug( "发送网关更新请求" );
                    SendGateUpdateRequest( );
                    break;
            }
        }

        /// <summary>
        /// 发送网桥更新请求
        /// </summary>
        protected virtual void SendBridgeUpdateRequest( )
        {
            //EflongLog.WriteMsg("base::SendBridgeUpdateRequest ... ", name);
        }

        /// <summary>
        /// 发送网关更新请求
        /// </summary>
        protected virtual void SendGateUpdateRequest( )
        {
            // EflongLog.WriteMsg("base::SendGateUpdateRequest ... ", name);
        }

        /// <summary>
        /// 文件修改过了
        /// </summary>
        /// <returns></returns>
        protected virtual bool IsFileTimeChanged( )
        {
            return false;
        }

        /// <summary>
        /// 文件修改过了
        /// </summary>
        /// <returns></returns>
        protected virtual bool IsFileTimeChanged2( )
        {
            return false;
        }

        /// <summary>
        /// 发送 Client 的查询请求
        /// </summary>
        protected void SendClientQueryRequsts( bool bForce )
        {
            if ( !bForce && manager.GetCoalMineUnitCount( ) > 0 && CoalMineUnitManager.Instance( ).IsRealDataReady )
            {
                return;
            }
            LogWrapper.Logger.Debug( "发送查询请求" );

            PacketAck packetAck;
            if ( manager.GetCoalMineUnitCount( ) == 0 )
            {
                // 没有联网矿信息

                packetAck = SendQueryCoalMineInfoRequst( );

                //autoReceived.Reset();
                LogWrapper.Logger.Debug( "SendQueryCoalMineInfoRequst" );
                packetAck = PerformCoalMineInfoAck( packetAck );
            }
            if ( manager.GetCoalMineUnitCount( ) > 0 )
            {
                int count = manager.GetCoalMineUnitCount( );
                for ( int nId = 1; nId <= count; nId++ )
                {
                    BaseCoalMineUnit coalMineUnit = manager.GetCoalMineUnit( nId );
                    if ( !IsRunning || !clientSocket.IsConnected( ) )
                    {
                        return;
                    }

                    if ( coalMineUnit == null )
                    {
                        Debug.Assert( coalMineUnit == null );
                        continue;
                    }
                    LogWrapper.Logger.Debug( "发送 DefinitionQueryRequst " + coalMineUnit.m_nId.ToString( ) );
                    packetAck = SendDefinitionQueryRequst( coalMineUnit.m_nId );

                    //autoReceived.Reset();
                    if ( coalMineUnit.m_nId == 1 )
                    {
                        //Debugger.Break();
                    }
                    PerformDefinitionQueryAck( packetAck );
                    LogWrapper.Logger.Debug( coalMineUnit.m_strName + " 测点数： " + coalMineUnit.GetMonitoringUnits( ).Count.ToString( ) );
                    if ( coalMineUnit.GetMonitoringUnits( ).Count > 0 )
                    {
                        LogWrapper.Logger.Debug( "发送 DataQueryRequst " + coalMineUnit.m_nId.ToString( ) );

                        //autoReceived.Reset();
                        packetAck = SendDataQueryRequst( coalMineUnit.m_nId );
                        PerformDataQueryAck( packetAck );
                    }
                }

                CoalMineUnitManager.Instance( ).IsRealDataReady = true;
                if ( onQueryCoalMineInfoCompleted != null )
                {
                    onQueryCoalMineInfoCompleted( this , new MessageEventArgs( ( uint )count ) );
                }
            }
        }

        /// <summary>
        /// 执行数据查询响应
        /// </summary>
        /// <param name="packetAck"></param>
        /// <returns></returns>
        private PacketAck PerformDataQueryAck( PacketAck packetAck )
        {
            if ( autoReceived.WaitOne( 10000 , false ) )
            {
                TakeCurrentPacketAck( packetAck );
                if ( packetAck.packetIn != null )
                {
                    DataAckStruct aDataAclStruct = DataAckStruct.ConverFromByteArray( packetAck.packetIn.GetpData( ) );
                    LogWrapper.Logger.Debug( "QUERYDATA " + aDataAclStruct.m_DataBase.m_nCoalMineId.ToString( ) );
                    DealDataAck( aDataAclStruct );
                }
            }
            return packetAck;
        }

        /// <summary>
        /// 执行测点定义查询响应
        /// </summary>
        /// <param name="packetAck"></param>
        /// <returns></returns>
        private PacketAck PerformDefinitionQueryAck( PacketAck packetAck )
        {
            if ( autoReceived.WaitOne( 10000 , false ) )
            {
                TakeCurrentPacketAck( packetAck );
                if ( packetAck.packetIn != null )
                {
                    DefinitionAckStruct aDefinitionAckStruct = new DefinitionAckStruct( );
                    try
                    {
                        aDefinitionAckStruct = DefinitionAckStruct.ConverFromByteArray( packetAck.packetIn.GetpData( ) );
                        LogWrapper.Logger.Debug( "处理测点定义，矿 Id= " + aDefinitionAckStruct.baseAck.m_nCoalMineId.ToString( ) );
                        DealDefinitionAck( aDefinitionAckStruct );
                    }
                    catch ( Exception ex )
                    {
                        LogWrapper.Logger.Error( "接受的测点定义数据包不够数, 矿Id= " + aDefinitionAckStruct.baseAck.m_nCoalMineId.ToString( ) );
                    }
                }
            }
            else
            {
                LogWrapper.Logger.Warn( "PerformDefinitionQueryAck 接收数据超时" );
            }
            return packetAck;
        }

        private PacketAck PerformDefinitionQueryAck( uint dwId )
        {
            PacketAck packetAck = null;
            if ( autoReceived.WaitOne( 5000 , false ) )
            {
                packetAck = this.clientThread.TakePacketActDeal( dwId );

                if ( packetAck.packetIn != null )
                {
                    DefinitionAckStruct aDefinitionAckStruct = new DefinitionAckStruct( );
                    try
                    {
                        aDefinitionAckStruct = DefinitionAckStruct.ConverFromByteArray( packetAck.packetIn.GetpData( ) );
                        LogWrapper.Logger.Debug( "QUERYDEFINITION " + aDefinitionAckStruct.baseAck.m_nCoalMineId.ToString( ) );
                        DealDefinitionAck( aDefinitionAckStruct );
                    }
                    catch ( Exception ex )
                    {
                        LogWrapper.Logger.Error( "接受的测点定义数据包不够数, 矿Id= " + aDefinitionAckStruct.baseAck.m_nCoalMineId.ToString( ) , ex );
                    }

                    BaseCoalMineUnit coalMineUint = manager.GetCoalMineUnit( aDefinitionAckStruct.baseAck.m_nCoalMineId );
                    if ( coalMineUint.GetMonitoringUnits( ).Count == 0 )
                    {
                        coalMineUint.m_bConnected = false;
                    }
                }
            }
            else
            {
                LogWrapper.Logger.Warn( "PerformDefinitionQueryAck 接收数据超时" );
            }
            return packetAck;
        }

        /// <summary>
        /// 执行联网矿信息查询响应
        /// </summary>
        /// <param name="packetAck"></param>
        /// <returns></returns>
        private PacketAck PerformCoalMineInfoAck( PacketAck packetAck )
        {
            if ( autoReceived.WaitOne( 12000 ) )
            {
                TakeCurrentPacketAck( packetAck );

                if ( packetAck.packetIn != null )
                {
                    LogWrapper.Logger.Debug( "QUERYCOALMINEINFO " + name );
                    CoalMineInfoStruct coalMineInfo = CoalMineInfoStruct.ConverFromByteArray( packetAck.packetIn.GetpData( ) );
                    DealCoalMineInfoAck( coalMineInfo );
                }
            }
            else
            {
                LogWrapper.Logger.Debug( "PerformCoalMineInfoAck WaitOne(12000) no packetAck.packetIn" );
            }
            return packetAck;
        }

        private void TakeCurrentPacketAck( PacketAck packetAck )
        {
            if ( packetAck.packetIn == null )
                packetAck = clientThread.TakePacketActDeal( packetAck.m_dwId );
            else
            {
                clientThread.TakePacketActDeal( packetAck.m_dwId );
            }
        }

        /// <summary>
        /// 发送查询联网矿信息请求
        /// </summary>
        public PacketAck SendQueryCoalMineInfoRequst( )
        {
            VizClientServer vcs = new VizClientServer( );
            vcs.m_dwMethodType = VizClientServer.VCS_MT_QUERYCOALMINEINFO;
            Packet packetRequest = new Packet( Marshal.SizeOf( vcs ) , vcs.GetByteArray( ) );

            PacketAck packetAck = SendRequst( packetRequest , VCS_MT_TYPES.VCS_MT_QUERYCOALMINEINFO );
            return packetAck;
        }

        /// <summary>
        /// 发生测点定义查询请求
        /// </summary>
        /// <param name="nId"></param>
        public PacketAck SendDefinitionQueryRequst( uint nId )
        {
            DefinitionQueryStruct aDefinitionQueryStruct = new DefinitionQueryStruct( );
            aDefinitionQueryStruct.baseStruct.m_nCoalMineId = nId;
            aDefinitionQueryStruct.baseStruct.m_dwMethodType = ( uint )VCS_MT_TYPES.VCS_MT_QUERYDEFINITION;
            aDefinitionQueryStruct.baseStruct.m_dwBufSize = 32;// sizeof(int) * 4 + sizeof(long) + sizeof(long) + MonUnitItem.SIZE_MONUNITID;// (uint)Marshal.SizeOf(aDefinitionQueryStruct.baseStruct) + (uint)Marshal.SizeOf(aItem);
            aDefinitionQueryStruct.baseStruct.m_dwNumOfItems = 0;
            Packet packetRequest = new Packet( aDefinitionQueryStruct.baseStruct.m_dwBufSize , aDefinitionQueryStruct.GetByteArray( ) );
            PacketAck packetAck = SendRequst( packetRequest , VCS_MT_TYPES.VCS_MT_QUERYDEFINITION );
            return packetAck;
        }

        /// <summary>
        /// 发生数据查询包
        /// </summary>
        /// <param name="nId"></param>
        public PacketAck SendDataQueryRequst( long nId )
        {
            DataQueryStruct aDataQueryStruct = new DataQueryStruct( );
            aDataQueryStruct.baseStruct.m_nCoalMineId = ( uint )nId;
            aDataQueryStruct.baseStruct.m_dwMethodType = ( uint )VCS_MT_TYPES.VCS_MT_QUERYDATA;
            aDataQueryStruct.baseStruct.m_dwBufSize = 32;// (uint)Marshal.SizeOf(aDataQueryStruct);
            aDataQueryStruct.baseStruct.m_dwNumOfItems = 0;
            Packet packetRequest = new Packet( aDataQueryStruct.baseStruct.m_dwBufSize , aDataQueryStruct.GetByteArray( ) );
            PacketAck packetAck = SendRequst( packetRequest , VCS_MT_TYPES.VCS_MT_QUERYDATA );
            return packetAck;
        }

        /// <summary>
        /// 发送请求
        /// </summary>
        /// <param name="packet"></param>
        /// <param name="type"></param>
        public PacketAck SendRequst( Packet packet , VCS_MT_TYPES type )
        {
            LogWrapper.Logger.Info( "发送数据包 : type= " + type.ToString( ) );
            autoReceived.Reset( );
            PacketAck packetAck = new PacketAck( packet );
            packetAck.type = ( uint )type;
            packetAck.m_dwId = clientThread.SendRequest( packetAck , type );
            return packetAck;
        }

        /// <summary>
        /// 发送请求
        /// </summary>
        /// <param name="packet"></param>
        /// <param name="type"></param>
        public PacketAck SendRequst( Packet packet , uint type )
        {
            LogWrapper.Logger.Info( "发送数据包 : type= " + type.ToString( ) );
            autoReceived.Reset( );
            PacketAck packetAck = new PacketAck( packet );
            packetAck.type = type;
            packetAck.m_dwId = clientThread.SendRequest( packetAck , type );
            return packetAck;
        }

        private void SetSysTimeToServer( Packet packet )
        {
            // 获取登录后的信息
            Packet aPacket = new Packet( packet.GetDataSize( ) , packet.GetpData( ) );
            byte[ ] datas = aPacket.GetpData( );
            if ( datas != null && datas.Length > 0 )
            {
                LoginStruct stLoginAck = LoginStruct.ConverFromByteArray( datas );
                if ( stLogin.length( ) == datas.Length )
                {
                    try
                    {
                        //  Eflong.Structure.SystemTime.SetSysTime(stLoginAck.m_stServer);
                    }
                    catch ( Exception ex )
                    {
                        LogWrapper.Logger.Error( "SetSysTimeToServer error" );
                        LogWrapper.Logger.Error( ex );
                    }
                    stLogin.m_stServer.year = stLoginAck.m_stServer.year;
                    stLogin.m_stServer.month = stLoginAck.m_stServer.month;
                    stLogin.m_stServer.dayofweek = stLoginAck.m_stServer.dayofweek;
                    stLogin.m_stServer.day = stLoginAck.m_stServer.day;
                    stLogin.m_stServer.hour = stLoginAck.m_stServer.hour;
                    stLogin.m_stServer.minute = stLoginAck.m_stServer.minute;
                    stLogin.m_stServer.second = stLoginAck.m_stServer.second;
                }
                else
                {
                    // 获取的登录信息不完整
                    Console.WriteLine( "!!!  获取的登录信息不完整" );
                }
            }
        }

        /// <summary>
        /// 网络是否正常，在3.5分钟内有实时数据接收
        /// </summary>
        private bool IsNetNormal( )
        {
            double d = DateTime.Now.Subtract( updateTime ).TotalSeconds;
            if ( d > ( DataChangedInterval + 0.5 ) * 60 )
            { // 60*3.5 ){
                // 3分钟内，没有接收到实时更新数据，可以网络有问题
                updateTime = DateTime.Now;
                return false;
            }
            return true;
        }

        /// <summary>
        /// 处理对联网系统的更新信息
        /// </summary>
        /// <param name="packet"></param>
        public void PerformUpdatePacket( Packet packet )
        {
            updateTime = DateTime.Now;
            if ( !Logined )
            {
                // 未登录成功，不更新数据，避免错误地更新数据
                LogWrapper.Logger.Debug( "PerformUpdatePacket end , not logined" );
                return;
            }
            LogWrapper.Logger.Debug( "PerformUpdatePacket ..." );
            IntPtr buffer = IntPtr.Zero;

            try
            {
                byte[ ] data = packet.GetpData( );
                buffer = Marshal.AllocCoTaskMem( data.Length );
                Marshal.Copy( data , 0 , buffer , data.Length );
                VizClientServer vcs = StructConvert.PtrToStruct<VizClientServer>( buffer );
                LogWrapper.Logger.Debug( "--> VizClientServer " + vcs.m_dwMethodType.ToString( ) );
                switch ( vcs.m_dwMethodType )
                {
                    case VizClientServer.VCS_NT_UPDATEDEFINITION:
                        {
                            try
                            {
                                // 更新测点定义
                                LogWrapper.Logger.Debug( "--> UpdateDefinitionFromByteArray " + " ... " );
                                uint nId = BaseCoalMineUnit.UpdateDefinitionFromByteArray( buffer );
                                if ( nId < 1 )
                                {
                                    LogWrapper.Logger.Error( "更新测点定义 error" );
                                }
                                else if ( onDefinitionChanged != null )
                                {
                                    onDefinitionChanged( this , new MessageEventArgs( nId ) );
                                }
                            }
                            catch ( Exception ex )
                            {
                                LogWrapper.Logger.Error( "更新测点定义" );
                                LogWrapper.Logger.Error( ex );
                            }
                        }
                        break;

                    case VizClientServer.VCS_NT_UPDATEDATA:
                        {
                            // 更新实时数据
                            try
                            {
                                LogWrapper.Logger.Debug( "--> UPDATEDATA " + " ... " );
                                uint nId = BaseCoalMineUnit.UpdateDataFromByteArray( buffer );
                                if ( nId < 1 )
                                {
                                    LogWrapper.Logger.Debug( "--> UPDATEDATA " + nId.ToString( ) + " error " );
                                }
                                else if ( onDataChanged != null )
                                {
                                    LogWrapper.Logger.Debug( "--> UPDATEDATA " + nId.ToString( ) + " Ok " );
                                    onDataChanged( this , new MessageEventArgs( nId ) );
                                }
                            }
                            catch ( Exception ex )
                            {
                                LogWrapper.Logger.Error( "更新实时数据" );
                                LogWrapper.Logger.Error( ex );
                            }
                        }
                        break;

                    case VizClientServer.VCS_NT_CONNECTIONSTATUSCHANGED:
                        {
                            // 更新联网状态
                            try
                            {
                                ConnectionStruct aConnectionStruct = StructConvert.PtrToStruct<ConnectionStruct>( buffer );

                                uint nId = ( uint )aConnectionStruct.m_nCoalMineId;
                                LogWrapper.Logger.Info( "CONNECTIONSTATUSCHANGED " + nId.ToString( ) );
                                BaseCoalMineUnit coalMineUint = manager.GetCoalMineUnit( nId );
                                if ( coalMineUint != null )
                                {
                                    coalMineUint.m_bConnected = aConnectionStruct.m_bConnected;
                                    coalMineUint.m_Time = DateTime.Now;
                                    if ( !coalMineUint.m_bConnected )
                                    {
                                        coalMineUint.HaltAllMonitoringUnits( );
                                        if ( onDataChanged != null )
                                        {
                                            MessageEventArgs e = new MessageEventArgs( nId );
                                            onDataChanged( this , e );
                                        }
                                    }
                                }
                                if ( onCoalMineChanged != null )
                                {
                                    onCoalMineChanged( this , new MessageEventArgs( nId ) );
                                }
                            }
                            catch ( Exception ex )
                            {
                                LogWrapper.Logger.Error( "更新联网状态" );
                                LogWrapper.Logger.Error( ex );
                            }
                        }
                        break;

                    case VizClientServer.VCS_NT_SENDDATA:

                        // 设置需要发送数据应答
                        LogWrapper.Logger.Info( "接到服务器的发送数据请求应答信号" );
                        m_checkSendDataAck.Set( );
                        break;
                }
            }
            catch ( Exception ex )
            {
                LogWrapper.Logger.Error( ex.Message );
            }
            finally
            {
                if ( buffer != IntPtr.Zero )
                {
                    Marshal.FreeCoTaskMem( buffer );
                }
                LogWrapper.Logger.Debug( "PerformUpdatePacket end" );
            }
        }

        /// <summary>
        /// 处理响应的数据包
        /// </summary>
        /// <param name="dataAck">响应的数据包</param>
        public void DealDataAck( DataAckStruct dataAck )
        {
            long nId = dataAck.m_DataBase.m_nCoalMineId;
            if ( nId == 25 )
            {
            }
            BaseCoalMineUnit coalMineUint = manager.GetCoalMineUnit( nId );
            if ( coalMineUint.GetMonitoringUnits( ).Count > 0 )
            {
                for ( int i = 0; i < dataAck.m_DataBase.m_dwNumOfItems; i++ )
                {
                    MonUnitData data = dataAck.m_DataItems[ i ].m_MonUnitData;
                    BaseMonitoringUnit monitorUnit = coalMineUint.GetMonitoringUnit( data.m_szId );
                    if ( monitorUnit != null )
                    {
                        monitorUnit.ConvertDataFromStruct( data );
                    }
                }
            }
        }

        /// <summary>
        /// 处理测点定义的响应包
        /// </summary>
        /// <param name="definition">测点定义的响应包</param>
        public void DealDefinitionAck( DefinitionAckStruct definition )
        {
            long nId = definition.baseAck.m_nCoalMineId;
            BaseCoalMineUnit coalMineUint = manager.GetCoalMineUnit( nId );
            if ( coalMineUint.GetMonitoringUnits( ).Count == 0 )
            {
                for ( int i = 0; i < definition.baseAck.m_dwNumOfItems; i++ )
                {
                    BaseMonitoringUnit monitorUnit = new BaseMonitoringUnit( );
                    MonUnitDefItem defItem = definition.m_DefItems[ i ];
                    monitorUnit.ConvertDefFromStruct( defItem.m_MonUnitDef );
                    coalMineUint.GetMonitoringUnits( ).Add( monitorUnit );
                }
            }
            else
            {
                List<string> list = new List<string>( );
                foreach ( var item in coalMineUint.GetMonitoringUnits( ) )
                {
                    list.Add( item.m_strId );
                }
                for ( int i = 0; i < definition.baseAck.m_dwNumOfItems; i++ )
                {
                    BaseMonitoringUnit monitorUnit = new BaseMonitoringUnit( );
                    MonUnitDefItem defItem = definition.m_DefItems[ i ];
                    monitorUnit.ConvertDefFromStruct( defItem.m_MonUnitDef );
                    if ( list.Contains( monitorUnit.m_strId ) )
                    {
                        list.Remove( monitorUnit.m_strId );
                    }
                    else
                    {
                        coalMineUint.GetMonitoringUnits( ).Add( monitorUnit );
                    }
                }

                // 清除不使用的测点
                for ( int i = 0; i < list.Count; i++ )
                {
                    coalMineUint.RemoveMonitoringUnit( coalMineUint.GetMonitoringUnit( list[ i ] ) );
                }
            }
            LogWrapper.Logger.Debug( "测点数： " + coalMineUint.GetMonitoringUnits( ).Count( ).ToString( ) );
        }

        /// <summary>
        /// 处理联网矿信息包
        /// </summary>
        /// <param name="coalMineInfo"></param>
        public void DealCoalMineInfoAck( CoalMineInfoStruct coalMineInfo )
        {
            for ( int i = 0; i < coalMineInfo.baseStruct.m_dwNumOfItems; i++ )
            {
                BaseCoalMineUnit coalMineUint = new BaseCoalMineUnit( );
                CoalMineInfoItem item = coalMineInfo.m_CoalMineInfoItems[ i ];
                coalMineUint.ConvertFromStruct( item );
                BaseCoalMineUnit coalMineUintOld = manager.GetCoalMineUnit( coalMineUint.m_nId );
                if ( coalMineUintOld == null )
                {
                    manager.AddCoalMineUnit( coalMineUint );
                }
                else
                {
                    // 修改数据
                    coalMineUintOld.m_strName = coalMineUint.m_strName;
                    coalMineUintOld.m_strIPAddr = coalMineUint.m_strIPAddr;
                }
            }
        }

        /// <summary>
        /// 投递异常信息
        /// </summary>
        /// <param name="exceptionMsg"></param>
        public void DisptchExceptionMessage( string exceptionMsg )
        {
            if ( this.IsRunning )
            {
                ThreadPool.QueueUserWorkItem( new WaitCallback( ExceptionDeal ) , exceptionMsg );
            }
        }

        /// <summary>
        /// 分派信息
        /// </summary>
        /// <param name="msg"></param>
        public void DispatchMessage( object msg )
        {
            if ( this.IsRunning )
            {
                ThreadPool.QueueUserWorkItem( new WaitCallback( this.MessageDeal ) , msg );
            }
        }

        /// <summary>
        /// 处理异常信息
        /// </summary>
        /// <param name="state"></param>
        public void ExceptionDeal( object state )
        {
            if ( this.IsRunning && this.onErrorDeal != null )
            {
                string msg = ( string )state;
                this.onErrorDeal( this , new MessageEventArgs( msg ) );
            }
            else
            {
                LogWrapper.Logger.Error( state );
            }
        }

        /// <summary>
        /// 处理信息
        /// </summary>
        /// <param name="state"></param>
        public void MessageDeal( object state )
        {
            if ( this.IsRunning && this.onMessageShow != null )
            {
                string msg = ( string )state;
                this.onMessageShow( this , new MessageEventArgs( msg ) );
            }
            else
            {
                LogWrapper.Logger.Info( state );
            }
        }

        /// <summary>
        /// 显示线程的异常信息
        /// </summary>
        /// <param name="status"></param>
        private void threadCallMessage( object state )
        {
            LogWrapper.Logger.Debug( state );

            string msg = DateTime.Now.ToLongTimeString( ) + " -> " + ( string )state;
            this.AddInfo( msg );
        }

        public void AddInfo( string message )
        {
            if ( !IsRunning )
            {
                return;
            }
            if ( this.form != null && this.lb_Info != null && this.lb_Info.InvokeRequired )
            {
                SetTextCallback d = new SetTextCallback( SetText );
                this.form.Invoke( d , new object[ ] { message } );
            }
        }

        public void SetText( string text )
        {
            if ( this.lb_Info != null )
            {
                if ( lb_Info.Items.Count > 1000 )
                {
                    lb_Info.Items.Clear( );
                }
                lb_Info.Items.Add( text );
                lb_Info.SelectedIndex = lb_Info.Items.Count - 1;
            }
        }

        public List<ListViewItem> GetUpdateListView( long nId )
        {
            List<BaseMonitoringUnit> units = manager.GetCoalMineUnit( nId ).GetMonitoringUnits( );

            return GetListViewItemsFromMonitoringUnits( units );
        }

        public static List<ListViewItem> GetListViewItemsFromMonitoringUnits( List<BaseMonitoringUnit> units )
        {
            List<ListViewItem> list = new List<ListViewItem>( );
            foreach ( BaseMonitoringUnit unit in units )
            {
                ListViewItem item = new ListViewItem( unit.m_strId );
                item.SubItems.Add( unit.m_strName );
                item.SubItems.Add( unit.m_Type.ToString( ) );

                if ( MonitoringUnitState.IsFault( unit.m_State ) )
                {
                    item.SubItems.Add( ( ( MonitoringUnitState.ChineseStates )unit.m_State ).ToString( ) );
                }
                else
                {
                    if ( unit.m_Modality == MonitoringUnitModality.Modalities.Digital )
                    {
                        item.SubItems.Add( unit.m_strStateName[ ( int )unit.m_State ] );
                    }
                    else
                    {
                        string s = string.Format( "{0:F2} {1}" , unit.m_fValue , unit.m_strUnit );
                        item.SubItems.Add( s );
                    }
                }
                item.SubItems.Add( unit.m_timeData.ToString( "dd-HH:mm:ss" ) );
                if ( unit.m_Modality == MonitoringUnitModality.Modalities.Digital )
                {
                    item.SubItems.Add( unit.m_strStateName[ 0 ] );
                    item.SubItems.Add( unit.m_strStateName[ 1 ] );
                    item.SubItems.Add( unit.m_strStateName[ 2 ] );
                    item.SubItems.Add( "" );
                    item.SubItems.Add( "" );
                    item.SubItems.Add( "" );
                }
                else
                {
                    item.SubItems.Add( string.Format( "{0:F2}" , unit.m_fUpperBound ) );
                    item.SubItems.Add( string.Format( "{0:F2}" , unit.m_fLowerBound ) );
                    item.SubItems.Add( string.Format( "{0:F2}" , unit.m_fUpperLimit ) );
                    item.SubItems.Add( string.Format( "{0:F2}" , unit.m_fLowerLimit ) );
                    item.SubItems.Add( string.Format( "{0:F2}" , unit.m_fBreakLimit ) );
                    item.SubItems.Add( string.Format( "{0:F2}" , unit.m_fRestLimit ) );
                }
                list.Add( item );
            }
            return list;
        }

        public enum ItemStates { None = 0 , 新增 = 1 , 修改 = 2 , 删除 = 3 , Update = 4 }

        public enum ItemIndexs
        {
            sensorName = 1 , sensorType = 2 , sValue = 3 ,
            sTime = 4 , sUnit = 2 , hightValue = 5 , lowValue = 6 ,
            hightLimit = 7 , lowLimit = 8 , breakValue = 9 , restValue = 10
        };

        ~Client( )
        {
            Dispose( false );
        }

        public void Dispose( )
        {
            Dispose( true );

            System.GC.SuppressFinalize( this );
        }

        protected virtual void Dispose( bool disposing )
        {
            if ( disposing )
            {
                // 这里是清理"托管资源"的用户代码段
                dispatcher = null;

                IsRunning = false;
                try
                {
                    m_checkLoginResetEvent.Close( );

                    m_checkConnectedResetEvent.Close( );

                    m_checkQueryCoalMineRequestAck.Close( );

                    m_checkQueryDataRequestAck.Close( );

                    m_checkQueryDefinitionRequestAck.Close( );

                    m_checkSendDataAck.Close( );
                }
                catch ( Exception ex )
                {
                    MessageBox.Show( "ResetEvent.Close() " + ex.Message );
                }

                try
                {
                    manager.Dispose( );
                }
                catch ( Exception ex )
                {
                    MessageBox.Show( "manager.Dispose() " + ex.Message );
                }

                try
                {
                    clientThread.Dispose( );
                }
                catch ( Exception ex )
                {
                    MessageBox.Show( "clientThread.Dispose() " + ex.Message );
                }
            }

            // 这里是清理"非托管资源"的用户代码段
        }
    }
}